package org.jsets.fastboot.util;

import java.util.Map;
import java.util.Objects;
import java.util.function.Consumer;

import org.springframework.context.ApplicationContext;
import org.springframework.core.env.Environment;

/**
 * spring context 静态持有类
 * 
 * @author wangjie (https://github.com/wj596)
 * @date 2021.07.10 21:57
 * @since 0.1
 */
public class SpringContextHolder {

	private static ApplicationContext applicationContext;
	private static Environment environment;

	public static void setApplicationContextIfNecessary(ApplicationContext applicationContext) {
		if (Objects.isNull(SpringContextHolder.applicationContext)) {
			SpringContextHolder.applicationContext = applicationContext;
		}
	}

	public static void setEnvironmentIfNecessary(Environment environment) {
		if (Objects.isNull(SpringContextHolder.environment)) {
			SpringContextHolder.environment = environment;
		}
	}

	public static ApplicationContext getApplicationContext() {
		checkApplicationContext();
		return applicationContext;
	}

	public static Environment getEnvironment() {
		checkEnvironment();
		return environment;
	}

	private static void checkApplicationContext() {
		if (applicationContext == null) {
			throw new IllegalStateException("applicaitonContext未注入");
		}
	}

	private static void checkEnvironment() {
		if (environment == null) {
			throw new IllegalStateException("environment未注入");
		}
	}

	public static <T> T getBean(Class<T> requiredType) {
		checkApplicationContext();
		return applicationContext.getBean(requiredType);
	}

	public static <T> T tryBean(Class<T> clazz) {
		checkApplicationContext();
		try {
			return applicationContext.getBean(clazz);
		} catch (Exception e) {
			// ignore
		}
		return null;
	}

	public static <T> Map<String, T> tryBeans(Class<T> clazz) {
		checkApplicationContext();
		try {
			return applicationContext.getBeansOfType(clazz);
		} catch (Exception e) {
			// ignore
		}
		return null;
	}

	public static <T> void tryBeanThen(Class<T> clazz, Consumer<T> consumer) {
		checkApplicationContext();
		if (applicationContext.getBeanNamesForType(clazz, false, false).length > 0) {
			consumer.accept(applicationContext.getBean(clazz));
		}
	}

	public static <T> void tryBeansThen(Class<T> clazz, Consumer<Map<String, T>> consumer) {
		checkApplicationContext();
		if (applicationContext.getBeanNamesForType(clazz, false, false).length > 0) {
			consumer.accept(applicationContext.getBeansOfType(clazz));
		}
	}

	public static boolean hasEnvironment() {
		if (environment == null) {
			return false;
		}
		return true;
	}

	public static String getProperty(String key) {
		if (hasEnvironment()) {
			return environment.getProperty(key);
		}
		return null;
	}

	public static String getProperty(String key, String defaultValue) {
		if (hasEnvironment()) {
			return environment.getProperty(key, defaultValue);
		}
		return null;
	}

	public static <T> T getProperty(String key, Class<T> targetType) {
		if (hasEnvironment()) {
			return environment.getProperty(key, targetType);
		}
		return null;
	}

	public static <T> T getProperty(String key, Class<T> targetType, T defaultValue) {
		if (hasEnvironment()) {
			return environment.getProperty(key, targetType, defaultValue);
		}
		return null;
	}
}